#pragma once

#include <utility>
#include "RBTree.hpp"

namespace my
{
	template<class Key, class Value, class CompareKey = less<Key>>
	class map
	{
		typedef std::pair<const Key, Value> ConstKeyType;
		typedef std::pair<Key, Value> NoConstKeyType;

		struct GetMapKey
		{
			const Key& operator()(const ConstKeyType& data) const
			{
				return data.first;
			}
		};
		typedef RBTree_base<ConstKeyType, Key, NoConstKeyType, GetMapKey, CompareKey> RBTree;
		RBTree _base;
		 
	public:

		typedef typename RBTree::iterator iterator;
		typedef typename RBTree::const_iterator const_iterator;
		typedef typename RBTree::reverse_iterator reverse_iterator;
		typedef typename RBTree::const_reverse_iterator const_reverse_iterator;

		iterator begin()
		{
			return iterator(_base.begin());
		}

		iterator end()
		{
			return  iterator(_base.end());
		}

		const_iterator begin() const
		{
			return const_iterator(_base.begin());
		}

		const_iterator end() const
		{
			return const_iterator(_base.end());
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(_base.rbegin());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(_base.rend());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(_base.rbegin());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(_base.rend());
		}

	public:

		map() = default;

		template<class InputIterator>
		map(InputIterator begin, InputIterator end)
			:_base(begin, end)
		{
			;
		}

		map(std::initializer_list<ConstKeyType> list)
			:_base(list)
		{
			;
		}

	public:

		Value& operator[](const Key& key)
		{
			iterator it = find(key);
			return it->second;
		}

		const Value& operator[](const Key& key) const
		{
			iterator it = find(key);
			return it->second;
		}

	public:

		bool empty() const
		{
			return _base.size() == 0;
		}

		size_t size() const
		{
			return _base.size();
		}

		const_iterator find(const Key& key) const
		{
			return _base.find(key);
		}

		iterator find(const Key& key)
		{
			return _base.find(key);
		}

		std::pair<iterator, bool> insert(const ConstKeyType& data)
		{
			bool get = _base.insert(data);
			return { iterator(_base.find(data.first)), get };
		}

		template<class InputIterator>
		void insert(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_base.insert(*first);
				++first;
			}
		}

		void insert(std::initializer_list<ConstKeyType> il)
		{
			for (const ConstKeyType& e : il)
			{
				_base.insert(e);
			}
		}

		size_t erase(const Key& key)
		{
			return _base.erase(key);
		}

		void erase(iterator first, iterator last)
		{
			while (first != last)
			{
				_base.insert(*first);
				++first;
			}
		}

		void clear()
		{
			_base.clear();
		}
	};
}
